package com.listeningframework.boot.autoconfigure.schedule;

import java.util.List;

import javax.sql.DataSource;

import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import com.google.common.collect.Lists;
import com.listeningframework.boot.autoconfigure.schedule.triggers.ListeningCronTriggerFactoryBean;
import com.listeningframework.boot.autoconfigure.schedule.triggers.ListeningSimpleTriggerFactoryBean;
import com.listeningframework.boot.autoconfigure.schedule.triggers.ListeningTriggers;

/**
 * 
 * Schedule Configuration
 *
 * @author lixining
 * @version $Id: ListeningScheduleConfiguration.java, v 0.1 2016年5月16日 下午6:44:28 lixining Exp $
 */
@Configuration
@EnableConfigurationProperties(ListeningQuartzClusterProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
@ConditionalOnProperty(prefix = "listening.schedule.cluster", name = "enabled", havingValue = "true", matchIfMissing = false)
public class ListeningQuartzClusterConfiguration {
    /**
     * DataSource
     */
    @Autowired
    private DataSource                       dataSource;
    /**
     * Platform Config
     */
    @Value("${spring.datasource.platform}")
    private String                           platform;
    /**
     * ListeningSimpleTriggerFactoryBean
     */
    @Autowired(required = false)
    private ListeningTriggers[]              listeningTriggers;
    /**
     * Quartz Configuration Properties
     */
    @Autowired
    private ListeningQuartzClusterProperties listeningQuartzClusterProperties;

    /**
     * Cluster Schedule
     *
     * @return SchedulerFactoryBean
     */
    @Bean(name = "clusterQuartzScheduler")
    public SchedulerFactoryBean getClusterQuartzScheduler() {
        // Schedule Table Schema
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.setContinueOnError(true);
        String schemaResource = "META-INF/schedule/" + platform + "/tables_" + platform + ".sql";
        populator.addScript(new ClassPathResource(schemaResource));
        DatabasePopulatorUtils.execute(populator, dataSource);

        // Scheduler Factory Bean
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setStartupDelay(20);
        schedulerFactoryBean.setDataSource(dataSource);
        schedulerFactoryBean.setQuartzProperties(listeningQuartzClusterProperties.getQuartzConfig());
        schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
        Trigger[] triggersArray = convertTriggers();
        if (triggersArray != null && triggersArray.length > 0) {
            schedulerFactoryBean.setTriggers(triggersArray);
        }
        return schedulerFactoryBean;
    }

    /**
     * Convert ListeningSimpleTriggerFactoryBean To Trigger Array
     */
    private Trigger[] convertTriggers() {
        List<Trigger> triggerList = Lists.newArrayList();
        if (listeningTriggers == null || listeningTriggers.length == 0) {
            return triggerList.toArray(new Trigger[triggerList.size()]);
        }
        for (ListeningTriggers tempTrigger : listeningTriggers) {
            triggerList.add(convertTrigger(tempTrigger));
        }
        return triggerList.toArray(new Trigger[triggerList.size()]);
    }

    /**
     * ListeningTriggers To Trigger
     */
    private Trigger convertTrigger(ListeningTriggers tempTrigger) {
        if (tempTrigger instanceof ListeningSimpleTriggerFactoryBean) {
            return ((ListeningSimpleTriggerFactoryBean) tempTrigger).getObject();
        }
        if (tempTrigger instanceof ListeningSimpleTriggerFactoryBean) {
            return ((ListeningCronTriggerFactoryBean) tempTrigger).getObject();
        }
        throw new RuntimeException("Not Supported Trigger Factory Bean");
    }

}
